﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using LowLevelGraphics;
using LowLevelGraphics.Filter;

using LowLevelGraphics.Types.Interval;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Creates a gray mask, showing contrast
    /// each pixel is compared with the edge created by the darkest and brightest color
    /// </summary>
    public class ContrastMask : BaseImageFilter
    {
        protected bool m_bGrayMode = true;
        protected bool m_bGlobalContrast = true;
        protected int m_nWindowSize = 13;

        /// <summary>
        /// constructor
        /// </summary>
        public ContrastMask()
        {
        }

        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <param name="_contrastMask"></param>
        internal ContrastMask(ContrastMask _contrastMask)
        {

        }

        /// <summary>
        /// Gets or sets if gray mode or color mode is used
        /// </summary>
        public bool GrayMode
        {
            get { return m_bGrayMode; }
            set { m_bGrayMode = value; }
        }

        /// <summary>
        /// Gets or sets if global contrast mode is used
        /// </summary>
        public bool GlobalContrastMode
        {
            get { return m_bGlobalContrast; }
            set { m_bGlobalContrast = value; }
        }

        /// <summary>
        /// Gets or sets window size for local contrast mask
        /// </summary>
        public int WindowSize
        {
            get { return m_nWindowSize; }
            set { m_nWindowSize = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;

            if (m_bGlobalContrast)
            {
                GlobalContrast(_bitmap, nWidth, nHeight);
            }
            else
            {
                LocalContrast(_bitmap, nWidth, nHeight);
            }
            return _bitmap;
        }

        /// <summary>
        /// Local contrast
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <param name="nWidth"></param>
        /// <param name="nHeight"></param>
        private void LocalContrast(UnsafeBitmap _bitmap, int nWidth, int nHeight)
        {
            Color colorMin = Definitions.Black;
            Color colorMax = Definitions.White;

            Color colorMinFound = Definitions.White;
            Color colorMaxFound = Definitions.Black;
            Color color = Color.Transparent;

            UnsafeBitmap bitmapCloned = (UnsafeBitmap)_bitmap.Clone();
            int x = 0;
            int y = 0;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    int xTemp = 0;
                    int yTemp = 0;
                    int xRel = m_nWindowSize;
                    int yRel = m_nWindowSize;
                    int nMinDist = int.MaxValue;
                    int nMaxDist = int.MaxValue;
                    for (int yWin = -m_nWindowSize / 2; yWin < m_nWindowSize / 2; yWin++)
                    {
                        for (int xWin = -m_nWindowSize / 2; xWin < m_nWindowSize / 2; xWin++)
                        {
                            xTemp = xRel + xWin;
                            yTemp = yRel + yWin;

                            if (xTemp > nWidth - 1) break;
                            if (xTemp < 0) break;
                            if (yTemp > nHeight - 1) break;
                            if (yTemp < 0) break;

                            color = bitmapCloned.GetPixel(xTemp, yTemp);
                            int nTempMin = ColorFunctions.DistanceSquared(color, colorMin);
                            int nTempMax = ColorFunctions.DistanceSquared(color, colorMax);
                            if (nTempMin < nMinDist)
                            {
                                nMinDist = nTempMin;
                                colorMinFound = color;
                            }
                            if (nTempMax < nMaxDist)
                            {
                                nMaxDist = nTempMax;
                                colorMaxFound = color;
                            }
                        }
                    }
                    int nDistance = (int)(nMaxDist - nMinDist * 2);
                    color = _bitmap.GetPixel(x, y);
                    nDistance = ColorFunctions.DistanceSquared(color, colorMax);
                    if (m_bGrayMode)
                    {
                        _bitmap.SetGrayPixel(x, y, nDistance / 765);
                    }
                    else
                    {
                        _bitmap.SetPixel(x, y, Color.FromArgb(nDistance));
                    }
                }
            }
            bitmapCloned.Dispose();
        }

        /// <summary>
        /// Global contrast
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <param name="nWidth"></param>
        /// <param name="nHeight"></param>
        private void GlobalContrast(UnsafeBitmap _bitmap, int nWidth, int nHeight)
        {
            Color colorMin = Definitions.Black;
            Color colorMax = Definitions.White;

            Color colorMinFound = Definitions.White;
            Color colorMaxFound = Definitions.Black;

            int nMinDist = int.MaxValue;
            int nMaxDist = int.MaxValue;

            int x = 0;
            int y = 0;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    Color color = _bitmap.GetPixel(x, y);
                    int nTempMin = ColorFunctions.DistanceSquared(color, colorMin);
                    int nTempMax = ColorFunctions.DistanceSquared(color, colorMax);
                    if (nTempMin < nMinDist)
                    {
                        nMinDist = nTempMin;
                        colorMinFound = color;
                    }
                    if (nTempMax < nMaxDist)
                    {
                        nMaxDist = nTempMax;
                        colorMaxFound = color;
                    }
                }
            }

            int nDistance = colorMaxFound.ToArgb() - colorMinFound.ToArgb() * 2;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    Color color = _bitmap.GetPixel(x, y);
                    nDistance = ColorFunctions.DistanceSquared(color, colorMax);

                    if (m_bGrayMode)
                    {
                        _bitmap.SetGrayPixel(x, y, nDistance / 765);
                    }
                    else
                    {
                        _bitmap.SetPixel(x, y, Color.FromArgb(nDistance));
                    }
                }
            }
        }

        /// <summary>
        /// Used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ContrastMask(this);
        }
    }
}
